package com.luobd.bpm.business.process.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.luobd.bpm.business.process.entity.CoreProcessDef;
import com.luobd.bpm.business.process.input.ProcessTaskPageInput;
import com.luobd.bpm.business.process.input.TaskCommandInput;
import com.luobd.bpm.business.process.service.IProcessDefService;
import com.luobd.bpm.business.process.service.IProcessTaskService;
import com.luobd.bpm.command.TaskRecallCmd;
import com.luobd.bpm.common.CurrentRequestHolder;
import com.luobd.bpm.common.ResponseData;
import com.luobd.bpm.common.ResponsePageData;
import com.luobd.bpm.dto.ProcessTaskDTO;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Primary
public class ProcessTaskServiceImpl implements IProcessTaskService {

    @Resource
    private IProcessDefService processDefService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private ManagementService managementService;


    @Override
    public ResponseData<Boolean> start(String id) {
        Random random = new Random();
        Authentication.setAuthenticatedUserId(String.valueOf(CurrentRequestHolder.get().getUserInfoId()));
        CoreProcessDef def = processDefService.getById(id);
        int anInt = random.nextInt(10);
        System.out.println(anInt);
        Map<String,Object> map = new HashMap<>();
        map.put("a",anInt);
        String formatted = LocalDateTimeUtil.formatNormal(LocalDateTime.now());
        ProcessInstance start = runtimeService.createProcessInstanceBuilder()
                .processDefinitionId(def.getProcessDefinitionId())
                .processDefinitionKey(def.getProcessKey())
                .businessKey(UUID.fastUUID().toString())
                .name(formatted + "_" + def.getName())
                .variables(map)
                .start();
        return ResponseData.success(start.getId() != null);
    }

    @Override
    public ResponsePageData<ProcessTaskDTO> page(ProcessTaskPageInput input) {
        TaskQuery taskQuery = taskService.createTaskQuery();

        // 同时存在候选人和候选组时
        if(StrUtil.isNotBlank(input.getAssignee()) && CollectionUtil.isNotEmpty(input.getGroups())) {
            taskQuery.taskAssignee(input.getAssignee()).or().taskCandidateGroupIn(input.getGroups());
        }else if(CollectionUtil.isNotEmpty(input.getGroups())) {
            taskQuery.taskCandidateGroupIn(input.getGroups());
        }else if(StrUtil.isNotBlank(input.getAssignee())) {
            taskQuery.taskAssignee(input.getAssignee());
        }
        long count = taskQuery.count();
        List<Task> list = taskQuery.orderByTaskCreateTime().desc().listPage(input.getStart(), input.getPageSize());
        List<ProcessTaskDTO> result = list.stream().map(ProcessTaskDTO::new).collect(Collectors.toList());
        if(CollectionUtil.isNotEmpty(result)) {
            Set<String> set = result.stream().map(ProcessTaskDTO::getProcessInstanceId).collect(Collectors.toSet());
            List<ProcessInstance> instances = runtimeService.createProcessInstanceQuery().processInstanceIds(set).list();
            Map<String, ProcessInstance> map = instances.stream().collect(Collectors.toMap(ProcessInstance::getId, Function.identity()));
            for (ProcessTaskDTO dto : result) {
                ProcessInstance instance = map.get(dto.getProcessInstanceId());
                if(instance != null) {
                    dto.setTitle(instance.getName());
                    dto.setStartUserId(instance.getStartUserId());
                }
            }
        }

        return ResponsePageData.success(result,count);
    }

    @Override
    public ResponseData<Boolean> resolveTask(TaskCommandInput input) {
        switch (input.getCommandType()) {
            case COMPLETE:
                taskService.complete(input.getTaskId());
                break;
            case RECALL:
                HistoricTaskInstance instance = historyService.createHistoricTaskInstanceQuery().taskId(input.getTaskId()).singleResult();
                if(instance == null) {
                    return ResponseData.error("任务不存在");
                }
                String currentTask = getLastUserTaskIdByCurrentTask(input.getTaskId(), instance.getProcessInstanceId());
                if(StrUtil.isBlank(currentTask)) {
                    return ResponseData.error("当前已经为第一个审批任务,无法撤回");
                }
                TaskRecallCmd recallCmd = new TaskRecallCmd(currentTask);
                managementService.executeCommand(recallCmd);
                break;
            default:
                throw new ActivitiException("未识别的任务处理类型" + input.getCommandType());
        }
        return ResponseData.success(Boolean.TRUE);
    }

    @Override
    public ResponseData<List<ProcessTaskDTO>> historyList(String processInstanceId) {
        List<ProcessTaskDTO> result = Lists.newArrayList();
        // 查询已审批的结点
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId).list();
        for (HistoricTaskInstance task : list) {
            ProcessTaskDTO dto = new ProcessTaskDTO(task);
            result.add(dto);
        }
        // 查询已审批的结点
        return ResponseData.success(result);
    }

    @Override
    public ResponseData<Boolean> recallTaskByProcessId(String processInstanceId) {

        List<HistoricTaskInstance> instances = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).list();


        System.out.println(instances);


        return null;
    }


    protected String getLastUserTaskIdByCurrentTask(String currentTaskId,String processInstanceId) {
        List<HistoricTaskInstance> listed = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).finished().orderByHistoricTaskInstanceEndTime().asc().list();
        if(CollectionUtil.isNotEmpty(listed)) {
            return listed.get(0).getId();
        }
        return null;
    }
}
